package com.zyz.system.service.question.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zyz.common.core.constants.Constants;
import com.zyz.common.core.enums.ResultCodeEnum;
import com.zyz.common.core.model.TableDataInfo;
import com.zyz.common.security.exception.ServiceException;
import com.zyz.system.elasticsearch.QuestionRepository;
import com.zyz.system.manager.QuestionCacheManager;
import com.zyz.system.mapper.question.QuestionMapper;
import com.zyz.system.model.question.Question;
import com.zyz.system.model.question.dto.QuestionAddDTO;
import com.zyz.system.model.question.dto.QuestionEditDTO;
import com.zyz.system.model.question.dto.QuestionQueryDTO;
import com.zyz.system.model.question.es.QuestionES;
import com.zyz.system.model.question.vo.QuestionDetailVO;
import com.zyz.system.model.question.vo.QuestionVO;
import com.zyz.system.service.question.IQuestionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
public class QuestionServiceImpl implements IQuestionService {

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private QuestionRepository questionRepository;

    @Autowired
    private QuestionCacheManager questionCacheManager;

    @Override
    public TableDataInfo list(QuestionQueryDTO queryDTO) {
        String questionIdsStr = queryDTO.getQuestionIdsStr();
        if (StringUtils.hasLength(questionIdsStr)) {
            String[] quesIdsStr = questionIdsStr.split(Constants.SPLIT_QUESTION_IDS);
            // 转Long类型
            Set<Long> quesIdsSet = Arrays.stream(quesIdsStr).map(Long::parseLong).collect(Collectors.toSet());
            queryDTO.setExcludeQuestionIds(quesIdsSet);
        }
        // 使用pagehelper来自动帮我们处理分页功能（自动帮忙修改我们的sql语句，在后买你拼接limit x,x）
        PageHelper.startPage(queryDTO.getPageNumber(), queryDTO.getPageSize());
        List<QuestionVO> questionVOList = questionMapper.selectQuestionList(queryDTO);
        if (questionVOList == null || questionVOList.isEmpty()) {
            return TableDataInfo.empty();
        }
        // 通过pageInfo拿到符合分页查询到的数据，并通过getTotal拿到个数
        long total = new PageInfo<>(questionVOList).getTotal();
        return TableDataInfo.success(questionVOList,total);
    }

    @Override
    public void add(QuestionAddDTO queryAddDTO) {
        // 将dto数据转换
        Question question = queryDTOToQuestion(queryAddDTO);
        // 查询题目标题是否有重复
        List<Question> questionByTitle = selectByTitle(question.getTitle());
        if (questionByTitle != null && !questionByTitle.isEmpty()) {
            log.error("题目添加失败，标题重复，题目标题: {}" , question.getTitle() );
            throw new ServiceException(ResultCodeEnum.FAILED_QUESTION_TITLE_EXISTS);
        }
        int row = questionMapper.insert(question);
        if (row != 1) {
            // 抛异常
            log.error("题目添加失败，题目标题: {}", question.getTitle());
            throw new ServiceException(ResultCodeEnum.ERROR);
        }
        // 将题目同步到elasticsearch
        QuestionES questionES = BeanUtil.copyProperties(question, QuestionES.class);
        questionRepository.save(questionES);
        questionCacheManager.addCache(question.getQuestionId());

    }

    @Override
    public QuestionDetailVO detail(Long questionId) {
        Question question = selectById(questionId);
        if (question == null) {
            log.error("未查询到该题目，题目id: {}",questionId);
            throw new ServiceException(ResultCodeEnum.FAILED_NOT_EXISTS);
        }

        return questionToDetailVo(question);
    }

    @Transactional
    @Override
    public void edit(QuestionEditDTO questionEditDTO) {
        Question question = selectById(questionEditDTO.getQuestionId());
        if (question == null) {
            log.error("未查询到要修改的题目，题目id: {}",questionEditDTO.getQuestionId());
            throw new ServiceException(ResultCodeEnum.FAILED_NOT_EXISTS);
        }
        question.setTitle(questionEditDTO.getTitle());
        question.setContent(questionEditDTO.getContent());
        question.setQuestionCase(questionEditDTO.getQuestionCase());
        question.setDifficulty(questionEditDTO.getDifficulty());
        question.setSpaceLimit(questionEditDTO.getSpaceLimit());
        question.setTimeLimit(questionEditDTO.getTimeLimit());
        question.setMainFunc(questionEditDTO.getMainFunc());
        question.setDefaultCode(questionEditDTO.getDefaultCode());
        int row = questionMapper.updateById(question);
        if (row != 1) {
            log.error("修改题目失败，题目id: {}",questionEditDTO.getQuestionId());
            throw new ServiceException(ResultCodeEnum.ERROR);
        }
        // 修改过后再次查询  如果根据标题查询有两相同的标题，则修改失败抛出异常
        List<Question> questions = selectByTitle(question.getTitle());
        if (questions.size() > 1) {
            // 表示标题  不唯一
            log.error("修改题目失败，题目标题重复，题目id: {}",questionEditDTO.getQuestionId());
            throw  new ServiceException(ResultCodeEnum.FAILED_QUESTION_TITLE_EXISTS);
        }
        // 将题目同步到elasticsearch
        QuestionES questionES = BeanUtil.copyProperties(question, QuestionES.class);
        log.info("同步es:{}",questionES);
        questionRepository.save(questionES);
    }

    @Override
    public void delete(Long questionId) {
        // 查询题目是否存在
        Question question = selectById(questionId);
        if (question == null) {
            log.error("未查询到要删除的题目，题目id: {}",questionId);
            throw new ServiceException(ResultCodeEnum.FAILED_NOT_EXISTS);
        }
        int row = questionMapper.deleteById(questionId);
        if (row != 1) {
            log.error("删除题目失败，题目id: {}",questionId);
            throw new ServiceException(ResultCodeEnum.ERROR);
        }
        // 从es中删除题目
        questionRepository.deleteById(questionId);
        questionCacheManager.removeCache(questionId);
        //  删除redis中热榜对应的改题目排名信息
        questionCacheManager.removeHotQuestionId(questionId);
    }


    private Question selectById(Long questionId) {
        return questionMapper.selectById(questionId);
    }

    private List<Question> selectByTitle(String title) {
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<Question>().eq(Question::getTitle, title);
        return questionMapper.selectList(queryWrapper);
    }

    private QuestionDetailVO questionToDetailVo(Question question) {
        QuestionDetailVO questionDetailVO = new QuestionDetailVO();
        questionDetailVO.setQuestionId(question.getQuestionId());
        questionDetailVO.setTitle(question.getTitle());
        questionDetailVO.setDifficulty(question.getDifficulty());
        questionDetailVO.setTimeLimit(question.getTimeLimit());
        questionDetailVO.setSpaceLimit(question.getSpaceLimit());
        questionDetailVO.setContent(question.getContent());
        questionDetailVO.setQuestionCase(question.getQuestionCase());
        questionDetailVO.setDefaultCode(question.getDefaultCode());
        questionDetailVO.setMainFunc(question.getMainFunc());
        return questionDetailVO;
    }

    private Question queryDTOToQuestion(QuestionAddDTO queryAddDTO) {
        Question question = new Question();
        question.setTitle(queryAddDTO.getTitle());
        question.setContent(queryAddDTO.getContent());
        question.setQuestionCase(queryAddDTO.getQuestionCase());
        question.setDifficulty(queryAddDTO.getDifficulty());
        question.setSpaceLimit(queryAddDTO.getSpaceLimit());
        question.setTimeLimit(queryAddDTO.getTimeLimit());
        question.setMainFunc(queryAddDTO.getMainFunc());
        question.setDefaultCode(queryAddDTO.getDefaultCode());
        return question;
    }
}
